﻿using System;

//
// Created by Arosy on 2021/12/13.
//

//
// Created by Arosy on 2021/12/13.
//


public delegate void CODERUN(JavaThread javaThread, BytecodeStream bytecodeStream, ref int index);

public class CodeRunBase
{
	//public static CODERUN[] run = Arrays.InitializeWithDefaultInstances<CODERUN>(256);
	public static CODERUN[] run = new CODERUN[256];
    public static void initCodeRun()
	{
		run[DefineConstants.NOP] = funcNOP; // NOP枚举值为0
		run[DefineConstants.DUP] = funcDUP;
		run[DefineConstants.RETURN] = funcRETURN;
		run[DefineConstants.GETSTATIC] = funcGETSTATIC;
		run[DefineConstants.ICONST_0] = funcICONST0;
		run[DefineConstants.PUTSTATIC] = funcPUTSTATIC;
		run[DefineConstants.LDC] = funcLDC;
		run[DefineConstants.DUP] = funcDUP;
		run[DefineConstants.ALOAD_0] = funcALOAD0;
		run[DefineConstants.ALOAD_1] = funcALOAD1;
		run[DefineConstants.NEW] = funcNEW;
		run[DefineConstants.INVOKEVIRTUAL] = funcINVOKEVIRTUAL;
		run[DefineConstants.INVOKESPECIAL] = funcINVOKESPECIAL;
	}
	public static void funcNOP(JavaThread javaThread, BytecodeStream bytecodeStream, ref int index)
	{
	//nothing to do .
	}
	public static void funcGETSTATIC(JavaThread javaThread, BytecodeStream bytecodeStream, ref int index)
	{
		Console.Write("    *执行指令GETSTATIC\n");
		ushort opera = bytecodeStream.readByTwo(ref index); //取出操作数
		Console.Write("\t\tconstantPool index is:{0:D}\n", opera);
		string className = bytecodeStream.getBelongMethod().getBelongKlass().getConstantPool().getClassNameByFieldInfo(opera); // 根据操作数 从 常量池获取类名
		string fieldName = bytecodeStream.getBelongMethod().getBelongKlass().getConstantPool().getFieldName(opera); // 根据操作数 从 常量池获取变量名
		Console.Write("\t\tclassName:{0},fieldName:{1}\n", className, fieldName);
		InstanceKlass klass = BootClassLoader.loadKlass(className); //根据类名取得加载完的klass对象
		CommonValue commonValue = klass.staticValue[fieldName]; // 根据变量名取出 值
		javaThread.stack.Peek().stack.Push(new CommonValue(commonValue.type,  commonValue.val)); //将前面取出的值推向栈顶
	}
	public static void funcPUTSTATIC(JavaThread javaThread, BytecodeStream bytecodeStream, ref int index)
	{
		Console.Write("    **执行指令PUTSTATIC\n");
		ushort opera = bytecodeStream.readByTwo(ref index); //取出操作数
		Console.Write("\t\tconstantPool index is:{0:D}\n", opera);
		string className = bytecodeStream.getBelongMethod().getBelongKlass().getConstantPool().getClassNameByFieldInfo(opera); // 根据操作数 从 常量池获取类名
		string fieldName = bytecodeStream.getBelongMethod().getBelongKlass().getConstantPool().getFieldName(opera); // 根据操作数 从 常量池获取变量名
		Console.Write("\t\tclassName:{0},fieldName:{1}\n", className, fieldName);
		CommonValue value = javaThread.stack.Peek().pop(); //弹出栈顶变量
		InstanceKlass klass = BootClassLoader.loadKlass(className); //根据类名取得加载完的klass对象
		klass.staticValue[fieldName] = value; //将从栈顶获得的静态变量写入类
	}
	public static void funcLDC(JavaThread javaThread, BytecodeStream bytecodeStream, ref int index)
	{
		Console.Write("    **执行指令LDC\n");
		byte opera = bytecodeStream.readByOne(ref index); //取出操作数
		byte tag = (bytecodeStream.getBelongMethod().getBelongKlass().getConstantPool().tag[opera]); //从常量池的类型中取出本次ldc指令操作的数据类型
		switch (tag)
		{
			case DefineConstants.CONSTANT_Float:
				break;
			case DefineConstants.CONSTANT_String:
			{
				byte indexs =(byte) bytecodeStream.getBelongMethod().getBelongKlass().getConstantPool().data[opera]; //从常量池获取索引
//C++ TO C# CONVERTER CRACKED BY X-CRACKER 2017 TODO TASK: C# does not have an equivalent to pointers to value types:
//ORIGINAL LINE: sbyte *str = bytecodeStream->getBelongMethod()->getBelongKlass()->getConstantPool()->getAndNewFromPool(index);
				String str = bytecodeStream.getBelongMethod().getBelongKlass().getConstantPool().getAndNewFromPool((ushort)indexs); //从常量池获取string的内容
				javaThread.stack.Peek().stack.Push(new CommonValue(DefineConstants.T_OBJECT,  str)); //入栈
				break;
			}
			case DefineConstants.CONSTANT_Class:
				break;
			default:
				Console.Write("未知类型\n");
				break;
		}
	}
	public static void funcICONST0(JavaThread javaThread, BytecodeStream bytecodeStream, ref int index)
	{
		javaThread.stack.Peek().stack.Push(new CommonValue(DefineConstants.T_INT, 0)); // 将int类型的0推向栈顶
	}
	public static void funcDUP(JavaThread javaThread, BytecodeStream bytecodeStream, ref int index)
	{
		Console.Write("    **执行指令dup\n");
		CommonValue cv = javaThread.stack.Peek().stack.Pop(); //获取栈顶值
		javaThread.stack.Peek().stack.Push(cv); // 推向栈顶
	}
	public static void funcALOAD0(JavaThread javaThread, BytecodeStream bytecodeStream, ref int index)
	{
		Console.Write("    **执行指令aload0\n");
		CommonValue cv = javaThread.stack.Peek().locals[0]; //获取局部变量表第一个数据
		javaThread.stack.Peek().stack.Push(cv); // 推向栈顶
	}
	public static void funcALOAD1(JavaThread javaThread, BytecodeStream bytecodeStream, ref int index)
	{
		Console.Write("    **执行指令aload1\n");
		CommonValue cv = javaThread.stack.Peek().locals[1]; //获取局部变量表第一个数据
		javaThread.stack.Peek().stack.Push(cv); // 推向栈顶
	}
	public static void funcNEW(JavaThread javaThread, BytecodeStream bytecodeStream, ref int index)
	{
		Console.Write("    **执行指令NEW\n");
		ushort opera = bytecodeStream.readByTwo(ref index);
		string classPath = bytecodeStream.getBelongMethod().getBelongKlass().getConstantPool().getClassPath(opera);
		InstanceKlass klass = BootClassLoader.loadKlass(classPath);
		InstanceOop oop = InstanceKlass.allocateInstance(klass);
		javaThread.stack.Peek().stack.Push(new CommonValue(DefineConstants.T_NARROWOOP,  oop));
	}
	public static void funcINVOKEVIRTUAL(JavaThread javaThread, BytecodeStream bytecodeStream, ref int index)
	{
		Console.Write("    **执行指令INVOKEVIRTUAL\n");
		ushort opera = bytecodeStream.readByTwo(ref index);
		string className = bytecodeStream.getBelongMethod().getBelongKlass().getConstantPool().getClassNameByMethodInfo(opera); //获取类名
		string methodName = bytecodeStream.getBelongMethod().getBelongKlass().getConstantPool().getMethodNameByMethodInfo(opera); //获取方法名
		string descName = bytecodeStream.getBelongMethod().getBelongKlass().getConstantPool().getDescriptorNameByMethodInfo(opera); //获取方法描述
		Console.Write("\tclassName:{0},methodName:{1},descName:{2}\n", className, methodName, descName);
		int paramCount = 0; //初始化参数数量
//C++ TO C# CONVERTER CRACKED BY X-CRACKER 2017 TODO TASK: C# does not have an equivalent to pointers to value types:
//ORIGINAL LINE: sbyte **params = CodeRunBase::getParams(descName, javaThread->stack.top(),paramCount);
		string[] @params = CodeRunBase.getParams(descName, javaThread.stack.Peek(), ref paramCount); //解析参数
		InstanceKlass klass = BootClassLoader.loadKlass(className); //获取类全限定名
		MethodInfo m = JavaNativeInterface.getMethod(klass, methodName, descName); //根据方法名字和方法描述找到要调用的方法
		JavaNativeInterface.callVirtual(javaThread, m, paramCount, @params); //调用方法
	}
	public static void funcINVOKESPECIAL(JavaThread javaThread, BytecodeStream bytecodeStream, ref int index)
	{
		Console.Write("    **执行指令INVOKESPECIAL\n");
		ushort opera = bytecodeStream.readByTwo(ref index);
		string className = bytecodeStream.getBelongMethod().getBelongKlass().getConstantPool().getClassNameByMethodInfo(opera); //获取类名
		string methodName = bytecodeStream.getBelongMethod().getBelongKlass().getConstantPool().getMethodNameByMethodInfo(opera); //获取方法名
		string descName = bytecodeStream.getBelongMethod().getBelongKlass().getConstantPool().getDescriptorNameByMethodInfo(opera); //获取方法描述
		Console.Write("\tclassName:{0},methodName:{1},descName:{2}\n", className, methodName, descName);
		int paramCount = 0; //初始化参数数量
//C++ TO C# CONVERTER CRACKED BY X-CRACKER 2017 TODO TASK: C# does not have an equivalent to pointers to value types:
//ORIGINAL LINE: sbyte **params = CodeRunBase::getParams(descName, javaThread->stack.top(),paramCount);
		string[] @params = CodeRunBase.getParams(descName, javaThread.stack.Peek(), ref paramCount); //解析参数
		InstanceKlass klass = BootClassLoader.loadKlass(className); //获取类全限定名
		MethodInfo m = JavaNativeInterface.getMethod(klass, methodName, descName); //根据方法名字和方法描述找到要调用的方法
		if ((m.getAccessFlags() & 100000000) == 0x0100)
		{ //判断是否是本地方法
          //FUNNATIVE nativeFunc = (FUNNATIVE) CodeRunNative.map[m.getMethodName()]; //取出本地方法
            CODENATIVE nativeFunc = (CODENATIVE) CodeRunNative.map[m.getMethodName()]; //取出本地方法
            nativeFunc(paramCount,@params); //调用本地方法
			return;
		}
		JavaNativeInterface.callSpecial(javaThread, m, paramCount, @params); //调用方法
	}
	public static void funcRETURN(JavaThread javaThread, BytecodeStream bytecodeStream, ref int index)
	{
	//nothing to do .
		Console.Write("    **执行指令RETURN\n");
	}
	public static string[] getParams(string descriptor, JavaVFrame jf, ref int paramCount)
	{
		int start = descriptor.IndexOf("(");
		int end = descriptor.IndexOf(")");
		string paramStr = descriptor.Substring(start + 1, end - 1);
//C++ TO C# CONVERTER CRACKED BY X-CRACKER 2017 TODO TASK: C# does not have an equivalent to pointers to value types:
//ORIGINAL LINE: sbyte *split = std::strtok(const_cast<sbyte *>(paramStr.data()), ";");
//C++ TO C# CONVERTER CRACKED BY X-CRACKER 2017 TODO TASK: There is no equivalent to 'const_cast' in C#:
		//sbyte split = strtok(const_cast<sbyte>(paramStr.data()), ";");
		string[] split = strtok(paramStr, ";");
        while (split != null)
		{
			paramCount++;
			//split = std::strtok(null, ";");
		}
//C++ TO C# CONVERTER CRACKED BY X-CRACKER 2017 TODO TASK: C# does not have an equivalent to pointers to value types:
//ORIGINAL LINE: sbyte **res = reinterpret_cast<sbyte **>(new sbyte[paramCount+1]);
//C++ TO C# CONVERTER CRACKED BY X-CRACKER 2017 TODO TASK: There is no equivalent to 'reinterpret_cast' in C#:
		string[] res = new string[paramCount + 1]; //非静态方法的第一个参数用于是this指针，因此多申请一个内存
		for (int i = 0; i <= paramCount; i++)
		{
			res[i] = (string) jf.pop().val;
		}
		return res;
	}

    public static string[] strtok(string str,string delim)
    {
        return str.Split(delim[0]);
    }

}




public delegate void FUNNATIVE(int paramsCount, string[] @params);

//public delegate void CODERUN(JavaThread javaThread, BytecodeStream bytecodeStream, ref int index);